package com.wyk.Spring;

import java.beans.Introspector;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @AnnotationName: wykApplicationContext
 * @Description:
 * @Author: 初久
 * @Date: 2022/6/29 12:00
 **/
public class wykApplicationContext extends DefaultListableBeanFactory implements BeanFactory, BeanPostProcessor {

    private String[] configLocations;
    private BeanDefinitionReader reader;

    //单例的IoC容器缓存
    private Map<String, Object> factorySingletonObjects = new ConcurrentHashMap<>();

    //用来存储所有的被代理过的对象
    private Map<String, BeanWrapper> factoryBeanInstanceCache = new ConcurrentHashMap<>();

    private ArrayList<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public wykApplicationContext(String... configLocations) {

        this.configLocations = configLocations;

        try {
            refresh();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    @Override
    public void refresh() throws Exception {

        //1. 定位，定位配置文件
        reader = new BeanDefinitionReader(this.configLocations);

        //2. 加载配置文件，扫描相关的类，把它们封装成BeanDefinition
        List<BeanDefinition> beanDefinitions = reader.loadBeanDefinitions();

        //3. 注册，把配置信息放到beanDefinitionMap容器中（伪IOC容器）
        doRegisterBeanDefinition(beanDefinitions);

        //4. 初始化非懒加载的类
        doAutowired();

    }

    /**
     * @return void
     * @Author 初久
     * @Description //TODO 初始化非懒加载的类
     * @Date 22:09 2022/7/3
     * @Param []
     **/
    private void doAutowired() {

        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {

            String beanName = beanDefinitionEntry.getKey();

            if (!beanDefinitionEntry.getValue().isLazyInit()) {

                try {

                    getBean(Introspector.decapitalize(beanName));

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }

    }


    /**
     * @return void
     * @Author 初久
     * @Description //TODO 注册，把配置信息放到beanDefinitionMap容器中（伪IOC容器）
     * @Date 22:09 2022/7/3
     * @Param [beanDefinitions]
     **/
    private void doRegisterBeanDefinition(List<BeanDefinition> beanDefinitions) throws Exception {

        for (BeanDefinition beanDefinition : beanDefinitions) {

            String factoryBeanName = beanDefinition.getFactoryBeanName();

            if (beanDefinitionMap.containsKey(factoryBeanName)) {
                throw new Exception("bean名称：" + factoryBeanName + "已经存在");
            }

            if (BeanPostProcessor.class.isAssignableFrom(beanDefinition.getclazz())) {
                beanPostProcessorList.add((BeanPostProcessor) beanDefinition.getclazz().newInstance());
                // 通知方法不需要注册进容器中
                continue;
            }

            beanDefinitionMap.put(factoryBeanName, beanDefinition);
        }

    }

    /**
     * @return T
     * @Author 初久
     * @Description //TODO
     * @Date 22:10 2022/7/3
     * @Param [beanClass]
     **/
    @Override
    public <T> T getBean(Class<T> beanClass) throws Exception {

        return getBean(Introspector.decapitalize(beanClass.getSimpleName()));

    }


    /**
     * @return T
     * @Author 初久
     * @Description 依赖注入，读取BeanDefinition中的信息
     * 然后通过反射机制创建一个实例并返回
     * @Date 22:08 2022/7/3
     * @Param [beanName]
     **/
    @Override
    public <T> T getBean(String beanName) throws Exception {
        Objects.requireNonNull(beanName, "bean名称不能为空");

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);

        if (beanDefinition != null) {

            T instance = createBean(beanDefinition.getclazz(), beanName);
            BeanWrapper beanWrapper = new BeanWrapper(instance, instance.getClass());

            // 执行回调方法
            beanAware(instance);

            // 前置通知
            postProcessBeforeInitialization(beanName, instance);

            // 初始化操作
            initializationBean(instance);

            factoryBeanInstanceCache.put(beanName, beanWrapper);

            // 后置通知
            postProcessAfterInitialization(beanName, instance);

            // 依赖注入
            populateBean(instance.getClass(), instance);

            return instance;

        } else {
            throw new NullPointerException("不存在该bean对象" + beanName);
        }

    }

    /**
     * @return T
     * @Author 初久
     * @Description //TODO 实例化bean
     * @Date 22:08 2022/7/3
     * @Param [clazz, beanName]
     **/
    public <T> T createBean(Class<?> clazz, String beanName) throws Exception {

        //实例化对象
        T instance;

        if (factorySingletonObjects.containsKey(beanName)) {
            instance = (T) factorySingletonObjects.get(beanName);
        } else {
            instance = (T) clazz.newInstance();
            factorySingletonObjects.put(beanName, instance);
        }

        return instance;

    }

    public String[] getBeanDefinitionNames() {

        return beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);

    }

    public int getBeanDefinitionCount() {

        return this.beanDefinitionMap.size();

    }

    public Properties getConfig() {

        return this.reader.getconfigProperties();

    }


    /**
     * @return T
     * @Author 初久
     * @Description //TODO 前置通知
     * @Date 13:07 2022/7/4
     * @Param [beanName, bean]
     **/
    @Override
    public Object postProcessBeforeInitialization(String beanName, Object bean) {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessBeforeInitialization(beanName, bean);
        }
        return bean;
    }


    /**
     * @return T
     * @Author 初久
     * @Description //TODO 后置通知
     * @Date 13:07 2022/7/4
     * @Param [beanName, bean]
     **/
    @Override
    public Object postProcessAfterInitialization(String beanName, Object bean) {
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
            bean = beanPostProcessor.postProcessAfterInitialization(beanName, bean);
        }
        return bean;
    }


    /**
     * @return void
     * @Author 初久
     * @Description //TODO 依赖注入
     * @Date 13:07 2022/7/4
     * @Param [clazz, instance]
     **/
    public <T> void populateBean(Class<?> clazz, T instance) throws Exception {
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                field.set(instance, getBean(clazz));
            }
        }
    }

    /**
     * @return void
     * @Author 初久
     * @Description //TODO 回调方法
     * @Date 22:11 2022/7/3
     * @Param [bean]
     **/
    public void beanAware(Object bean) {
        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware) bean).Aware();
        }
    }

    /**
     * @return void
     * @Author 初久
     * @Description //TODO 初始化方法
     * @Date 22:11 2022/7/3
     * @Param [bean]
     **/
    public void initializationBean(Object bean) {
        if (bean instanceof InitializingBean) {
            ((InitializingBean) bean).afterPropertiesSet();
        }

    }

    public Map<String, Object> getFactorySingletonObjects() {
        return factorySingletonObjects;
    }

    public Map<String, BeanWrapper> getFactoryBeanInstanceCache() {
        return factoryBeanInstanceCache;
    }
}
